<!--
 * @Date: 2024-09-24 17:32:17
 * @Author: LiSong
 * @LastEditors: LiSong
 * @LastEditTime: 2024-12-19 10:32:16
 * @Description: 页面布局
-->
<template>
  <el-container
    :class="[
      'iv-layout-wrapper',
      showBorder ? 'iv-layout-border': '',
      enableAside ? 'has-aside' : '',
      enableHeader ? 'has-header' : '',
      mainLineState.moving ? 'main-line-move' : '',
      asideLineState.moving ? 'aside-line-move' : '',
    ]"
  >
    <!-- 顶部区域 -->
    <el-header
      v-if="enableHeader"
      :="headerAttrs"
      :style="headerStyles"
      class="iv-layout-header"
    >
      <!-- 顶部区域左侧 -->
      <div
        v-show="headerLeftEnable"
        :class="[
          'iv-layout-header-item',
          'iv-layout-header__left',
          designState ? 'iv-layout-header__design' : ''
        ]"
        :style="{
          'justify-content': headerLeftAlign
        }"
      >
        <slot v-if="$slots.header_left" name="header_left"></slot>
        <div v-else class="tips-text">slot="header_left"</div>
      </div>
      <!-- 顶部区域右侧 -->
      <div
        v-show="headerRightEnable"
        :class="[
          'iv-layout-header-item',
          designState ? 'iv-layout-header__design' : '',
          headerLeftEnable ? 'iv-layout-header__right' : '',
        ]"
        :style="{
          'justify-content': headerRightAlign
        }"
      >
        <slot v-if="$slots.header_left" name="header_right"></slot>
        <div v-else class="tips-text">slot="header_right"</div>
      </div>
      <!-- 顶部区域展开收起按钮 -->
      <div
        :class="[
          'iv-layout-header-item',
          'iv-layout-header__tools'
        ]"
        v-if="enableCondition"
      >
        <!-- 展开收起按钮：开启查询条件区域时开放 -->
        <el-button
          @click="conditionState.showCondition = !conditionState.showCondition"
        >
          <span>{{ conditionState.showCondition ? closeButtonText : openButtonText }}</span>
        </el-button>
      </div>
    </el-header>
    <el-container class="iv-layout-body">
      <div class="iv-layout-content">
        <!-- 左侧区域 -->
        <div class="iv-layout-left" v-show="enableAside" :style="{ '--var-aside-width': asideLineState.moveSizeX }">
          <!-- 左侧栏 -->
          <el-aside
            v-show="asideState.showAside"
            :="asideAttrs"
            :class="[
              'iv-layout-aside',
              (enableHeader && designState) ? 'iv-border__no-top' : ''
            ]"
          >
            <slot v-if="$slots.aside" name="aside"></slot>
            <div v-else class="tips-text">slot="aside"</div>
          </el-aside>
          <!-- 可拖拽的条 -->
          <div
            :class="[
              'iv-layout-aside__line',
              !(asideState.showAside && enableAside) ? 'aside-hidden' : ''
            ]"
            @click.stop.prevent="asideLineClick"
            @mouseup.stop.prevent="asideLineMouseUp"
            @mousedown.stop.prevent="asideLineMouseDown"
          >
            <el-icon v-show="asideState.showAside"><ArrowLeft /></el-icon>
            <el-icon v-show="!asideState.showAside"><ArrowRight /></el-icon>
          </div>
        </div>
        <!-- 右侧区域 -->
        <el-container class="iv-layout-main">
          <!-- 处理中间区域的顶部边框：头部启用 && 设计状态 && 条件区域展开时，顶部边框不隐藏 -->
          <el-main class=""
            :class="[
              (enableHeader && designState && !conditionState.showCondition) ? 'iv-border__no-top' : '',
              'iv-layout-main-center'
            ]"
          >
            <!-- 条件区域 -->
            <template v-if="enableCondition">
              <div class="main-condition"
                v-show="conditionState.showCondition"
                :style="{
                  'background-color': conditionBgColor
                }"
              >
                <!-- 条件区域-全量布局 -->
                <div v-if="$slots.condition" class="main-condition__full">
                  <slot name="condition"></slot>
                </div>
                <!-- 条件区域-左右布局 -->
                <div v-else class="main-condition__group" :style="conditionStyles">
                  <!-- 条件区域-左侧布局 -->
                  <div class="main-condition__group-item main-condition__left">
                    <div class="condition__left-center">
                      <slot v-if="$slots.condition_content" name="condition_content"></slot>
                      <div v-else class="tips-text left">slot="condition_content"</div>
                    </div>
                  </div>
                  <!-- 条件区域-右侧布局 -->
                  <div class="main-condition__group-item main-condition__right">
                    <div class="condition__right-center" :style="conditionRightStyles">
                      <slot v-if="$slots.condition_toolbar" name="condition_toolbar"></slot>
                      <div v-else class="tips-text left">slot="condition_toolbar"</div>
                    </div>
                  </div>
                </div>
              </div>
            </template>
            <!-- 中心区域 -->
            <div class="iv-layout-main-body">
              <div class="iv-layout-main-body__content">
                <template v-if="!openUpDownMain">
                  <div class="main-body-updown">
                    <slot v-if="$slots.main" name="main"></slot>
                  </div>
                </template>
                <template v-else>
                  <div class="main-body-updown" @mouseleave="mainLineMouseUp">
                    <div class="main-body-up" :style="{
                      'height': mainLineState.moveSizeY
                    }">
                      <slot v-if="$slots.main" name="main"></slot>
                    </div>
                    <div class="main-body-line"
                      @mouseup.stop="mainLineMouseUp"
                      @mousedown.stop="mainLineMouseDown"
                    >
                      <span>···</span>
                    </div>
                    <div class="main-body-down">
                      <slot v-if="$slots.main_down" name="main_down"></slot>
                    </div>
                    <div v-if="mainLineState.moved"
                      class="main-body-line-mark"
                      @mouseup.stop="mainLineMouseUp"
                      @mousemove.stop="mainLineMouseMove"
                    >
                    </div>
                  </div>
                </template>
              </div>
            </div>
          </el-main>
          <!-- 底部区域 -->
          <el-footer v-if="enableFooter" class="iv-layout-footer__wrapper">
            <slot v-if="$slots.footer" name="footer"></slot>
            <div v-else class="tips-text">slot="footer"</div>
          </el-footer>
        </el-container>
      </div>
    </el-container>
    <div v-if="asideLineState.moved"
      class="iv-layout-aside__line-mark"
      @mouseup.stop="asideLineMouseUp"
      @mousemove.stop="asideLineMouseMove"
    ></div>
    <slot></slot>
  </el-container>
</template>

<script setup>
import { computed, reactive, watch } from 'vue';
import { ArrowRight, ArrowLeft } from '@element-plus/icons-vue';

const props = defineProps({
  // 显示边框
  showBorder: { type: Boolean, default: false },
  // 是否为设计状态
  designState: { type: Boolean, default: false },
  // 启用侧边
  enableAside: { type: Boolean, default: true },
  // 启用头部
  enableHeader: { type: Boolean, default: true },
  // 启用底部
  enableFooter: { type: Boolean, default: false },
  // 侧边初始宽度
  asideWidth: { type: String, default: '300px'},
  // 头部左侧宽度
  headerLeftWidth: { type: [String], default: 'auto' },
  // 头部左侧对齐方式
  headerLeftAlign: { type: String, default: 'left' },
  // 头部左侧启用
  headerLeftEnable: { type: Boolean, default: true },
  // 头部右侧宽度
  headerRightWidth: { type: [String], default: 'auto' },
  // 头部右侧对齐方式
  headerRightAlign: { type: String, default: 'right' },
  // 头部左侧启用
  headerRightEnable: { type: Boolean, default: true },

  // 展开按钮文本
  openButtonText: { type: String, default: '展开条件' },
  // 收起按钮文本
  closeButtonText: { type: String, default: '收起条件' },
  // 启用查询区域
  enableCondition: { type: Boolean, default: false },
  // 展开查询区域
  expandCondition: { type: Boolean, default: false },
  // 搜索区域背景色
  conditionBgColor: { type: String, default: '#edf1fc' },
  // 查询区域右侧宽度
  conditionRightWidth: { type: String, default: '200px'},
  // 查询区域右侧对齐方式
  conditionRightAlign: { type: String, default: 'right' },

  // 开启主区域的上下布局
  openUpDownMain: { type: Boolean, default: false },
  // 中间上部区域高度
  mainUpHeight: { type: String }
})

const headerAttrs = reactive({
  height: '60px'
})
const headerStyles = computed(() => {
  const leftWidth = props.headerLeftWidth || 'auto'
  const rightWidth = props.headerRightWidth || 'auto'
  const colsMap = new Map()
  if (props.headerLeftEnable) {
    colsMap.set('lf', leftWidth)
  }
  if (props.headerRightEnable) {
    colsMap.set('lr', rightWidth)
  }
  if (props.enableCondition) {
    if (!colsMap.has('lf') && !colsMap.has('lr')) {
      colsMap.set('lt', 'auto')
    } else {
      colsMap.set('lt', '100px')
    }
  }
  const tempCols = []
  for (let value of colsMap.values()) {
    tempCols.push(value)
  }
  const resStyles = {
    'grid-template-columns': tempCols.join(' '),
  }
  return resStyles
})

const asideAttrs = reactive({
  width: props.asideWidth,
})
const asideState = reactive({
  showAside: true
})
const asideLineState = reactive({
  moved: false,
  moving: false,
  moveSizeX: props.asideWidth,
  tempSizeX: props.asideWidth,
})
const asideLineClick = () => {
  if (asideLineState.moving) return
  asideState.showAside = !asideState.showAside
  if (asideState.showAside) {
    asideAttrs.width = asideLineState.tempSizeX
    asideLineState.moveSizeX =  asideLineState.tempSizeX
  } else {
    asideLineState.moveSizeX = '0px'
  }
}
const asideLineMouseUp = (e) => {
  asideAttrs.width = asideLineState.moveSizeX;
  asideLineState.moved = false;
  setTimeout(() => { asideLineState.moving = false }, 100)
}
const asideLineMouseMove = (e) => {
  if (asideLineState.moved && asideState.showAside) {
    asideLineState.moving = true;
    asideLineState.moveSizeX = `${e.layerX}px`;
    asideLineState.tempSizeX = `${e.layerX}px`;
  }
}
const asideLineMouseDown = (e) => {
  asideLineState.moved = true;
}
// 监听左侧宽度
watch(
  () => props.asideWidth,
  (nv) => {
    asideAttrs.width = nv ? nv : '300px'
  },
  { deep: true, immediate: false }
)

const mainLineState = reactive({
  moved: false,
  moving: false,
  moveSizeY: 'calc((100% - 10px) / 2)',
})
const mainLineMouseUp = (e) => {
  mainLineState.moved = false
  setTimeout(() => {
    mainLineState.moving = false;
  }, 100)
}
const mainLineMouseDown = (e) => {
  mainLineState.moved = true;
}
const mainLineMouseMove = (e) => {
  if(!(mainLineState.moved)) return
  mainLineState.moving = true;
  mainLineState.moveSizeY = `${e.layerY}px`;
}
watch(
  () => props.mainUpHeight,
  (nv) => {
    mainLineState.moveSizeY = nv ? nv : 'calc((100% - 10px) / 2)'
  },
  { deep: true, immediate: false }
)

// 查询条件区域的数据集
const conditionState = reactive({
  showCondition: props.expandCondition
})
// 查询条件的个性样式
const conditionStyles = computed(() => {
  const rightWidth = props.conditionRightWidth || '200px'
  return {
    "grid-template-columns": `auto ${rightWidth}`
  }
})
// 查询条件右侧区域个性样式
const conditionRightStyles = computed(() => {
  let styles = {}
  const { conditionRightAlign } = props
  const alignStyle = {
    'alignItems': 'center',
    'justifyContent': 'right'
  }
  const alignValues = conditionRightAlign.split('#')
  if (alignValues && alignValues.length === 1) {
    alignStyle.justifyContent = alignValues[0]
  } else if (alignValues && alignValues.length > 1) {
    alignStyle.alignItems = alignValues[0]
    alignStyle.justifyContent = alignValues[1]
  }
  styles = {
    ...styles,
    ...alignStyle,
  }
  return styles
})
watch(
  () => props.expandCondition,
  (nv) => {
    conditionState.showCondition = nv
  },
  { deep: true, immediate: false }
)

</script>

<style lang="scss" scoped>
$borderColor: #dadada;
$solidBorder: 1px solid $borderColor;
$dashedBorder: 1px dashed $borderColor;

.tips-text {
  height: 100%;
  display: flex;
  font-size: 35px;
  align-items: center;
  justify-content: center;
  overflow: auto;
  &.left {
    justify-content: left;
  }
}
.iv-border__no-top {
  border-top: none !important;
}
.iv-layout-wrapper {
  width: 100%;
  height: 100%;
  padding: 8px;
  position: relative;
  background: #fff;
  &.has-header {
    padding-top: 0;
  }
  &.main-line-move {
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    cursor: row-resize;
  }
  &.aside-line-move {
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    cursor: col-resize;
  }
}
.iv-layout-header {
  width: 100%;
  display: grid;
  padding: 0;
  align-items: center;
  &-item {
    height: 100%;
    display: flex;
    align-items: center;
    overflow: auto;
    flex-wrap: wrap;
  }
  &__left {
    flex-wrap: nowrap;
  }
  &__tools {
    padding-left: 12px;
    justify-content: right;
  }
}
.iv-layout-body {
  position: relative;
}
.iv-layout-content {
  position: absolute;
  top: 0;
  width: 100%;
  height: 100%;
  display: flex;
}
.iv-layout-left {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  margin-right: 10px;
}
.iv-layout-aside {
  border: $solidBorder;
  &__line {
    position: absolute;
    top: 0;
    width: 10px;
    left: var(--var-aside-width);
    height: 100%;
    cursor: w-resize;
    z-index: 1000;
    display: flex;
    justify-content: center;
    align-items: center;
    &-mark {
      position: absolute;
      top: 0;
      width: 100%;
      height: 100%;
      background-color: #ffffff;
      opacity: 0.3;
      z-index: 800;
    }
    &.aside-hidden {
      border: $solidBorder;
      border-right: none;
    }
    &:hover {
      background-color: $borderColor;
    }
  }
}
.iv-layout-main {
  &-center {
    padding: 0;
    display: flex;
    flex-direction: column;
    border: $solidBorder;
  }
  &-body {
    flex: 1;
    min-height: 200px;
    position: relative;
    &__content {
      position: absolute;
      display: flex;
      top: 0;
      width: 100%;
      height: 100%;
    }
  }
}
.iv-layout-footer {
  &__wrapper {
    padding: 0;
    border: $solidBorder;
    border-top: none;
  }
  
}
.iv-layout-border {
  .iv-layout-header-item {
    border: $solidBorder;
  }
  .iv-layout-header__right,
  .iv-layout-header__tools {
    margin-left: -1px;
  }
  .iv-layout-header__design {
    padding: 0 2px;
  }
  .main-condition__right {
    border-left: $solidBorder;
  }
}
.main-condition {
  min-height: 60px;
  border-bottom: $solidBorder;
  &__full {
    padding: 8px;
  }
  &__group {
    width: 100%;
    height: 100%;
    display: grid;
    padding: 0;
    align-items: center;
    grid-template-columns: auto 200px;
    &-item {
      height: 100%;
      display: flex;
      flex-direction: column;
    }
  }
  &__left {
    .condition__left-center {
      flex: 1;
      padding: 8px;
      min-height: 20px;
    }
    :deep(.el-form) {
      display: grid;
      gap: 12px 12px;
      grid-template-columns: repeat(3, 1fr);
      height: 100%;
      align-items: center;
    }
  }
  &__right {
    display: block;
    .condition__right-center {
      flex: 1;
      padding: 8px;
      min-height: 20px;
      display: flex;
      flex-wrap: wrap;
      gap: 12px 12px;
      align-items: center;
      justify-content: right;
      :deep(.button-item) {
        margin: 0;
      }
    }
  }
  :deep(.el-form-item) {
    width: 100%;
    margin-right: 0 !important;
    margin-bottom: 0 !important;
  }
}
.main-body-updown {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  position: relative;
  flex-wrap: nowrap;
  .main-body-up {
    width: 100%;
    display: flex;
		flex-direction: column;
    min-height: 80px;
    height: calc((100% - 10px) / 2);
    overflow: hidden;
  }
  .main-body-down {
    flex: 1;
    width: 100%;
    min-height: 100px;
    display: flex;
		flex-direction: column;
  }
  .main-body-line {
    height: 10px;
    line-height: 10px;
    border: $solidBorder;
    border-left: none;
    border-right: none;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: row-resize;
    font-size: 14px;
    font-weight: 600;
    letter-spacing: 2px;
    &-mark {
      position: absolute;
      width: 100%;
      height: 100%;
      background-color: #ffffff;
      opacity: 0.3;
    }
    &:hover {
      background-color: $borderColor;
    }
  }
}

</style>
<style lang="scss">
.has-aside {
  .vxe-table--border-line {
    border-left: none;
    border-right: none;
  }
}
</style>
